% %!TEX encoding = UTF-8 Unicode
\chapter{Implementace}
\label{chap:implementation}

Ukázková implementace API v jazyce Java a příslušná dokumentace automaticky vygenerovaná pomocí
nástroje Javadoc je součástí této práce.
Konkrétní implementace pracuje s robotickým \wifi{} králíkem \nab.

\section{Hardwarové a systémové požadavky}
\label{sec:requirements}

Níže uvádíme seznam hardwarových a softwarových požadavků, které musí být
pro spuštění základní verze serveru a zprovoznění komunikace mezi
robotem a tímto serverem splněny. Dodatečné pluginy můžou tyto požadavky rozšiřovat.
\begin{itemize}
  \item Robot {\nab} (server nebyl testován s jinými verzemi robota).
  \item Počítač s {\wifi} kartou a nainstalovaným virtuálním strojem {\java}
  (Java Runtime Environment 1.6).
  \item Je-li na počítači, na němž má běžet server, zapnutý firewall, virtuální
  stroj {\java} musí mít povolena příchozí spojení na příslušném portu.
  \item {\wifi} síť, ke které se můžou připojit robot a počítač. {\nab}
  podporuje připojení k síti bez zabezpečení, příp. s šifrováním WEP nebo WPA (nikoli
  WPA2).
  \item Pro funkčnost některých komponent (porozumění textu, generování zpráv
  na základě vzorců) je potřeba mít nainstalovaný SWI-Prolog 5.10.4.
\end{itemize}

\section{Implementace jednotlivých vrstev}

\subsection*{Fyzická vrstva}

Fyzická vrstva je realizována ovladačem \lstinline!volk!, který zajišťuje obousměrnou komunikaci mezi ovládanými
zařízeními pomocí protokolu HTTP.

\subsection*{Interpretační vrstva}

V rámci interpretační vrstvy dochází ke konverzi sémantického popisu sdělení do volání příslušných metod fyzické
vrstvy. K tomu jsou určené komponenty, které implementují javovský interface \lstinline!Listener<Node>!,
např. třída \lstinline!NabaztagSimpleInterpreter!.

\subsection*{Vrstva porozumění jazyku}

Generický interface \lstinline!Understander<T extends Expression>! umožňuje
stan\-dar\-di\-zo\-vaný přístup k různým objektům, které
odpovídají za porozumění sdělením v~přirozeném jazyce. V této práci pojem
\textit{porozumění} výrazu znamená konverzi objektu
typu \lstinline!Expression! (představujícího text nebo zvuk) do objektu \lstinline!Node!, který
reprezentuje sdělení na tektogramatické
rovině.

\subsection*{Propojení interpretační vrstvy a vrstvy porozumění jazyku}

V rámci této práce jsme implementovali několik jednoduchých komponent, které integrují funkcionalitu obou zmíněných
vrstev. Mezi ně patří:
\begin{itemize}
 \item \lstinline!cz.cuni.mff.ufal.volk.RssInputProcessor! -- jednoduchá čtečka RSS zdrojů, robot předčítá nové zprávy,
 \item \lstinline!cz.cuni.mff.ufal.volk.ReaderInputProcessor! -- předčítání uživatelského vstupu.
\end{itemize}


\subsection*{Uživatelské rozhraní}

Vrstva uživatelského rozhraní zajišťuje přímou komunikaci systému s uživatelem. Sestává z následujících komponent:

\begin{itemize}
 \item \lstinline!cz.cuni.mff.ufal.volkapp.UserTextInput! -- komponenta pro načítání uživatelského vstupu v přírozeném
jazyce z konzoly,
 \item ovladač \lstinline!volk! -- umožňuje jednak přehrávání hlášek v při\-ro\-ze\-ném jazyce uživateli, jednak
zaznamenávání uživatelského hlasového vstupu (automatické roz\-poz\-ná\-vání řeči v těchto záznamech není zatím
implementováno).
\end{itemize}

\section{Logování a trasování}
\label{subsection:logging}

V této práci používáme pro logování výhradně knihovnu \lj{} (viz kapitola \ref{chap:technologies:log4j} na
stránce \pageref{chap:technologies:log4j} a příklady \ref{log_ex_01} a \ref{log_ex_02}).

Konvence pro logování, jimiž jsme se při vývoji serveru a nástrojů řídili:\footnote{Stejné konvence by se měly
dodržovat i při vývoji pluginů.}
\begin{itemize}
  \item Nepoužívají se žádné jiné způsoby logování kromě \lj{} (není zejména povoleno libovolné vypisování hlášek na
  standardní výstup).
  \item Používají se pouze úrovně logování standardní v knihovné \lj{} (TRACE, DEBUG, INFO, WARN, ERROR, FATAL, OFF).
  \item Všechny logovací záznamy jsou v anglickém jazyce (s výjimkou logování uživatelského vstupu). V budoucnu lze
  uvažovat o lokalizaci záznamů v logu.
  \item Každá třída má svůj vlastní static (společný pro všechny instance)
  logger. Příklad \ref{log_ex_01} na stránce \pageref{log_ex_01} ukazuje vytvoření a použití loggeru.\footnote{Pro
  zjednoduše\-ní práce doporučujeme přidat definici loggeru do šablony třídy v
  používa\-ném vývojovém prostředí.}
  \item Konfigurace logování se nastavuje pouze v konfiguračním souboru. Nelze
  ji měnit z kódu.
  \item Doporučujeme neměnit formát logování určený v příkladu.\footnote{Zvolený formát logování je vhodný pro
  jednoduché vyhledávání, třídění a strojové zpracování (na rozdíl od některých lokalizovaných formátů).}
\end{itemize}

Konfigurace logování v aplikaci \lstinline!volkapp! (viz kapitola \ref{chap:implementation:volkapp}) je možná na třech úrovních:
\begin{enumerate}
  \item Přednastavená konfigurace ve třídě \lstinline!BasicConfigurator! (logování záznamů všech úrovní na standardní
  výstup).
  \item Výchozí konfigurační soubor \lstinline!volkapp.log4j.txt! -- pokud existuje, aplikace se pokusí s jeho použitím
  konfigurovat logování.
  \item Konfigurační soubor, jehož cesta je zadána v beanu \lstinline!log4j! v konfiguračním souboru aplikace
  (\lstinline!volkapp.config.xml!) -- pokud existuje, aplikace se pokusí pomocí něj konfigurovat logování.
\end{enumerate}
\noindent
Podporována je pouze konfigurace pomocí souborů typu \textit{properties}. Selže-li krok $1$ (což by se nikdy nemělo
stát), aplikace se vůbec nespustí. Selže-li krok $2$ nebo $3$, bude použita poslední  správná konfigurace. Loguje se i
při načítání konfiguračního souboru Spring Frameworku (\lstinline!volkapp.config.xml!), takže několik prvních záznamů
bude zalogováno pomocí základní konfigurace, resp. pomocí konfigurace, která se nachází v souboru \lstinline!volkapp.log4j.txt!.

\section{Internacionalizace}

V dnešní době se při vývoji aplikací klade velký důraz na přizpůsobení softwarového produktu pro uživatele z různých
zemí, mluvící různými jazyky.
Podle \cite{ms:localization:01} je vývoj softwaru s podporou více jazyků založen na dvou prvcích:

\begin{description}
\item[Globalizace a lokalizovatelnost (\textit{World-Readiness})] je způsob vývoje programů tak, aby je bylo možné
jednoduše lokalizovat bez nutnosti zásahů do zdrojového kódu. Uživatelský vstup a~výs\-tup by měly být naprogramovány
nezávisle na konkrétním přiroze\-ném jazyce.
\item[Lokalizace (\textit{Localization})] je především překlad softwaru, ale také přizpůsobení aplikace k~po\-žadavkům
konkrétního trhu. Kromě překladu hlášek určených pro uživatele se může jednat o změnu velikosti některých grafických
prvků (např. kvůli tomu, že text v daném jazyce je kratší nebo delší než v~původním), změnu rozmístění grafických prvků
(např. při překladu aplikace do jazyka, který je zapisován zprava doleva), korektní formátování čísel a času
atd.
\end{description}

Veškerá komunikace s uživatelem je připravena pro lokalizaci -- všechna hlášené pro uživatele jsou umístěny do
\textit{.properties} souborů.

Informace v logu a zprávy obsažené ve výjimkác nejsou primárně určeny pro konečné uživatele, nýbrž pro administrátory
a~vyvojáře. Z~tohoto důvodu logování a systém výjimek nebyly lokalizovány: všechny zprávy jsou v angličtině.


\section{Debugování}

Pro vývoj a debugování těch částí aplikace, které byly napsány v Javě, jsme používali vývojová prostředí Eclipse 3.5 a
Eclipse 3.7\footnote{Vývojové prostředí je dostupné z: \url{http://www.eclipse.org/}. Dobrý úvod do problematiky
debugování v prostředí Eclipse: \url{http://www.ibm.com/developerworks/library/os-ecbug/}.} a standardní nástroje pro
lokální debugování, které jsou součástí prostředí. K vývoji dalších nástrojů a ladění jejich spolupráce s
ostatními moduly je možné zapojit vzdálené debugování (\textit{remote debugging}).

Pro debugování kódu napsaného v Prologu jsme používali:
\begin{enumerate}
 \item SWI-Prolog a Emacs\footnote{\url{http://www.gnu.org/s/emacs/}} k debugování formální gramatiky češtiny.
 \item Jednoduché spouštěcí prostředí tuPrologu vytvořené pomocí technologie Java Web
Start\footnote{\url{http://tuprolog.sourceforge.net/jws/tuprolog2.4.0.jnlp}} pro debugování kódu, který odpovídá za
generování zpráv na základě vzorců. To sice neposkytuje tak pokročilé možnosti jako SWI-Prolog, nicméně
kvůli nekompatibilitě obou dialektů jazyka nelze obě prostředí libovolně zaměňovat.\footnote{Kód funkční v tuPrologu by
měl správně běžet pod SWI Prologem, nikoli ale naopak.}
\end{enumerate}

Na ladění a hledání chyb v jednodušších vzorcích stačí přidání nových unit testů, které upozorní programátora
na případné rozdíly mezi očekávaným a skutečným výsledkem. Ve složitějších případech lze v konfiguraci aplikace
aktivovat logování úrovně \lstinline!DEBUG!, potom se bude při volání metody \lstinline!evaluate! logovat prologovský
kód, který se použije pro konkretizaci proměnných. Ten ze dál ladit samostatně.

\section{Automatické testy}

Pro následující komponenty byly sestaveny automatické testy:

\begin{sourcecodedesc}
\item[nlpat] -- sada klasických unit testů, pracujících v prostředí JUnit frameworku,
\item[tool\_langr] -- testy úspěšnosti rozpoznávání jazyka psaného textu, nejedná se o jednotkové testy,
nýbrž o samostatnou aplikaci.
\end{sourcecodedesc}

\section{Vydání distribuce}

Pro vydání distribuce (sady spustitelných \textit{jar} souborů), stejně jako pro vygenerování dokumentace
\textit{javadoc}, jsme používali standardní nástroje pro export, které jsou součástí vývojového prostředí Eclipse. 
\begin{enumerate}
  \item Aplikaci \lstinline!volkapp! jsme vyexportovali jako spustitelný \textit{jar} soubor\footnote{Ang.
  \textit{Runnable JAR file}.} s volbou, aby se všechny závislé knihovny kopírovaly do podsložky.\footnote{Ang.
  \textit{Copy required libraries into a sub-folder next to generated JAR}.} Došlo k vytvoření souboru
  \lstinline!volkapp.jar! a složky \lstinline!volkapp_lib!.
  \item Ostatní knihovny jsme vyexportovali jako obyčejné \textit{jar} soubory do složky \lstinline!volkapp_lib!
  vytvořené  v předchozím kroku.
\end{enumerate}

Standardní dokumentaci \textit{javadoc} jsme vyexportovali s výchozím nastavením najednou pro všechny knihovny.

\section{Přehled komponent}

\begin{figure}[ht!]
\centering
\includegraphics{images/pkg_all.png}
\caption{Přehled implementovaných komponent a závislostí mezi nimi. Uprostřed se nachází knihovna
\lstinline!volkcore!, na které jsou závislé všechny ostatní komponenty.}
\label{04:packages}
\end{figure}

\subsection{Obecné API -- \texttt{volkcore}}

Tato knihovna obsahuje obecné typy a rozhraní jednotlivých vrstev a služeb (viz obrázek \ref{04:packages}).
% \begin{sourcecodedesc}
% \item[]
% \end{sourcecodedesc}

\subsection{Aplikační framework -- \texttt{volkapp}}
\label{chap:implementation:volkapp}

Součástí této práce je jednoduchý aplikační kontejner \lstinline!volkapp!, který spouští ovladač králíka \nab{} (viz
\ref{chap:implementation:volk}) a poskytuje jednotlivé služby na základě konfigurace (kompatibilní se Spring Frameworkem). Konfigurace musí
být v XML formátu a musí se nacházet v~souboru \lstinline!volkapp.config.xml! -- ve složce, kde se nachází aplikace.
Inicializaci, spuštění serveru, konfiguraci logování a zpřístupnění služeb zajišťuje aplikace, není tedy potřeba přistupovat přímo k objektům
Spring Frameworku. Následuje seznam standardních konfiguračních položek -- beanů (názvy povinných položek jsou uvedeny
hvězdičkami; za dvojtečkou následuje typ beanu):
\begin{sourcecodedesc}
\item[*applicationSettings: ApplicationSettings] Glo\-bální nastavení aplikace. Zatím umožňuje určit
pouze lokalizaci komunikace s uživatelem, především používaný jazyk.
\item[*components: List<Component>] Seznam komponent (objektů, které implementují rozhraní
\lstinline!cz.cuni.mff.ufal.volk.Component!). Ve výchozí konfiguraci obsahuje ovladač aplikace a komponentu, která
umožňuje čtení a další zpracovávání uživatelského vstupu.
\item[log4j: String] Cesta k \textit{properties} souboru, který obsahuje konfiguraci logování pro log4j framework
(viz kapitola \ref{chap:technologies:log4j} a příklad \ref{log_ex_02}). Pokud tato položka chybí, použije se výchozí
konfigurační soubor \lstinline!volkapp.log4j.txt!.
\item[*services: Map<String, Object>] Seznam zaregistrovaných služeb (jako mapování názvů na implementace).
Tabulka \ref{tab:030:services:std} obsahuje výpis standardních služeb zaregistrovaných v systému ve výchozí konfiguraci.
\end{sourcecodedesc}

\begin{table}[ht!]
\begin{tabular}{|p{3cm}|p{10.4cm}|}
\hline
Název & Popis \\ \hline
\lstinline!volk.tts! & Generování řeči na základě psaného textu. \\ \hline
\lstinline!volk.langrec! & Rozpoznávání jazyka textu nebo mluvené řeči (obecně objektu typu \lstinline!Expression!). \\
\hline
\lstinline!volk.sndconv! & Konverze mezi různými zvukovými formáty. \\ \hline
\lstinline!volk.stdout! & Uživatelský standardní výstup (typicky konzola nebo prvek okna ovládací aplikace). \\ \hline
\end{tabular}
\caption{Standardní služby dostupné v systému.}
\label{tab:030:services:std}
\end{table}

\noindent
Spuštění aplikace (volání static metody \lstinline!cz.cuni.mff.ufal.volkapp.Main.main!) probíhá následujícím způsobem:
\begin{enumerate}
  \item Načtení logování pomocí konfiguračních souborů (viz \ref{subsection:logging}).
  \item Vytvoření všech beanů ze seznamu \lstinline!components! a jejich spuštění pomocí asynchronní metody
  \lstinline!open()! z rozhraní \lstinline!cz.cuni.mff.ufal.volk.Component!.
\end{enumerate}

Aplikace běží, dokud některá komponenta nezavolá metodu \lstinline!close()! objektu
\lstinline!cz.cuni.mff.ufal.volkapp.Application!. Při vypínání aplikace bude na každém spuštěném beanu zavolána metoda
zaregistrovaná v konfiguračním souboru jako \textit{destroy-method} (existuje-li). Tyto metody by nikdy
neměly generovat výjimky (všechny výjimky musí být odchyceny, příp. i zalogovány). Pořadí volání těchto metod není
specifikováno.\footnote{Tím pádem implementace těchto metod nesmí nic předpokládat o tom, zda už proběhlo volání pro
jiné beany.}

K inicializaci seznamu zaregistrovaných služeb (bean \lstinline!services!) a glo\-bálních nastavení aplikace
(bean \lstinline!applicationSettings!) může dojít v libovolném okamžiku po~spuštění aplikace, nejpozději však při prvním
pokusu o jejich použití.\footnote{Jedná se o volání jedné z následujících metod:\begin{itemize}
\item \lstinline!ApplicationSettings.getCurrent()!, 
\item \lstinline!Services.registered()!, 
\item \lstinline!Servives.get(name,T)!.
\end{itemize}} Implementace všech těchto metod umožňuje jejich bez\-pečné použití z více vláken bez nutnosti dodatečné synchronizace volání.

\begin{figure}
\dirtree{%
.1 volk/.
.2 volkapp.jar.
.2 volkapp.config.xml.
.2 volkapp.log4j.txt.
.2 volkapp\_lib/.
.3 volkcore.jar.
.3 commons-logging-1.1.1.jar.
.3 commons-logging-adapters-1.1.1.jar.
.3 commons-logging-api-1.1.1.jar.
.3 log4j-1.2.16.jar.
.3 org.springframework.asm-3.0.5.RELEASE.jar.
.3 org.springframework.beans-3.0.5.RELEASE.jar.
.3 org.springframework.context-3.0.5.RELEASE.jar.
.3 org.springframework.core-3.0.5.RELEASE.jar.
.3 org.springframework.expression-3.0.5.RELEASE.jar.
.3 \textnormal{pluginy (ovladač, služby) a jejich závislosti}.
}
\caption{Adresářová struktura. Přehled obsahuje hlavní binární soubor \texttt{\footnotesize{volkapp.jar}}, povinné
konfigurační soubory a závislosti.}
\end{figure}

\subsection{Rozhraní pro formální gramatiky -- \texttt{nlu\_prolog}}

Tato knihovna umožňuje používání formálních gramatik napsaných v jazyce prolog pro
porozumění uživatelskému vstupu. Vyžaduje SWI Prolog nainstalovaný v~systému; teoreticky by knihovna
\lstinline!nlu_prolog! měla fungovat i~s~jinými distribucemi tohoto jazyka kompatibilními s JPL, byla ale
testována pouze s SWI Prologem.

Parser přirozeného jazyka musí být naprogramován v Prologu a musí definovat proceduru
\lstinline!parse/2!, jejíž parametry jsou popsány v tabulce \ref{par:parse_2}.

\begin{table}[ht!]
\begin{tabular}{|m{1.9cm}|m{11.5cm}|}
\hline
Parametr & Popis \\ \hline
\lstinline!+Sentence! & Seznam tokenů, který reprezentuje vstupní větu. \\
\hline \lstinline!-IL! & Výsledek parsování. Parametr se má unifikovat
se strukturou \lstinline!node(Sem, Attr, Children)!, kde:
\begin{itemize}
  \item \lstinline!Sem! je tzv. význam uzlu -- atom.
  \item \lstinline!Attr! je seznam atributů ve tvaru \lstinline!Key-Value!
  (např. u sloves \lstinline!mood-imp! znamná rozkazovací způsob). Pořadí atributů
  není důležité.
  \item \lstinline!Children! je seznam struktur \lstinline!node/3!.
  Pořadí v seznamu \lstinline!Children! může, ale nemusí hrát roli při
  interpretaci (záleží na konkrétní implementaci sémantické analýzyzž).
\end{itemize}
\\
\hline
\end{tabular}
\caption{Specifikace parametrů procedury \lstinline!parse/2!.}
\label{par:parse_2}
\end{table}

Součástí této práce je ukázková implementace -- jednoduchý parser
českého jazyka, který zpracovává mj. příkazy pro robotického králíka \nab -- ukázka viz tabulka
\ref{ex:understanding_cz_01}.
\
\begin{table}[ht!]
\catcode`\-=12
\begin{tabular}{|p{5.5cm}|p{7.9cm}|}
\hline
Věta v češtině & Výsledek parsování \\ \hline
\textit{mávni levým uchem} & \multirow{2}{*}{\parbox{7.9cm}{Příslušná interpretace v mezijazyce (viz kapitola
\ref{chap:proj:intlang}).}}\\ \cline{1-1} \textit{rozsviť levé světýlko červeně} & \\ \hline
\textit{mávni levé uchem} & Neúspěch kvůli chybnému pádu pří\-dav\-né\-ho jména. Implementovaný parser češtiny neumí
zacházet s nekorektně sestavenými větami.
\\
\hline
\end{tabular}
\caption{Příklady výstupů ukázkového parseru českého jazyka. Na interpukci a
velikosti písmen nezáleží. Česká diakritika je nicméně vyžadována.}
\label{ex:understanding_cz_01}
\end{table}

\subsection{HTTP server -- \texttt{volkhs}}

\lstinline!Volkhs! je jednoduchý, obecně použitelný HTTP server, který umožňuje nízkoúrovňové
zpracovávání dotazů a generování odpovědí. Na požadavky může zpracovávat poža\-davky ve
více vláknech (jejich maximální počet je konfigurovatelný).

Nejdůležitější třídy komponenty \lstinline!volkhs!:

\begin{sourcecodedesc}
\item[HttpServer] Hlavní třída HTTP serveru. Zajišťuje nízkoúrovňovou komunikaci -- příjem požadavků, jejich zpracování
a odesílání odpovědí. Jedná se o~implementaci návrhového vzoru pozorovatel \cite{pecinovsky001}. Každá instance
serveru musí mít právě jednoho pozorovatele typu \lstinline!HttpRequestHandler!. Pozorovatele nelze pro vytvořenou
instanci serveru změnit.
\item[HttpRequestHandler] Pozorovatel, který zpracovává konkrétní požadavky a generuje odpovědi. Poskytuje jednu
metodu \lstinline!process!, kterou server volá  při přijetí HTTP požadavku. Její parametry jsou popsány v tabulce
\ref{tab:040:params:process}
\end{sourcecodedesc}

\begin{table}[ht!]
\begin{tabular}{|m{3cm}|m{10.4cm}|}
\hline
Parametr & Popis \\ \hline
\lstinline!request! & Výsledek parsování HTTP dotazu -- informace o po\-u\-žité metodě a hodnotách jednotlivých POST a
GET parametrů. \\ \hline
\lstinline!response! & Objekt, který umožňuje jak nastavit parametry odpovědi, mj. kód (typicky \lstinline!200 OK!)
a HTTP hlavičky, tak odeslat v jejím těle binární data. \\ \hline
\end{tabular}
\caption{Popis parametrů metody \lstinline!HttpRequestHandler.process!.}
\label{tab:040:params:process}
\end{table}

\subsection{Ovladač králíka {\nab} -- \texttt{volk}}
\label{chap:implementation:volk}

Ovladač zařízení je implementován jako třída \lstinline!NabaztagControllerImpl!
(součást knihovny \lstinline!volk.jar!,
balík \lstinline!cz.cuni.mff.ufal.volk!), která může být použita libo\-vol\-ným
programem (nebo knihovnou) napsaným v
Javě. Umožňuje vysokoúrovňovou komunikaci s jedním nebo více roboty:
příjem a odesílání zvuku, reakce na
zmáčknutí tlačítka, rozsvěcení světýlek a nastavení pozic uší. Obousměrná přímá
komunikace se samotným zařízením probíhá
pomocí protokolu HTTP.

Objekt ovladače může být sdílen více vlákny, není třeba synchronizovat přístup; ovšem třeba dbát na to, aby k volání
jednotlivých metod docházelo pouze ve správném stavu -- viz následující oddíl.

\subsection*{Stavy ovladače}

Ovladač se může nacházet v jednom ze dvou stavů:
\begin{description}[font=\normalfont\itshape]
\item[vypnuto]V tomto stavu se ovladač nachází bezprostředně po svém vytvoření, nebo po zastavení
pomocí metody \lstinline!close()!. Ve stavu
\textit{vypnuto} ovladač nekomunikuje se zařízeními, umožňuje ale změnu
nastavení.
\item[zapnuto]V tomto stavu ovladač poslouchá na definovaném portu a umožňuje
komunikovat s roboty. Pokus o změnu
nastavení v tomto stavu způsobí výjimku.
\end{description}

Přechody mezi stavy zajišťují metody \lstinline!open()! a \lstinline!close()!:\footnote{Pokus o zavolání těchto metod ve
špatném stavu skončí výjimkou.}

\begin{sourcecodedesc}
\item[void open()] Zapne server (ovladač), začne poslouchat na definovaném
portu. Tuto metodu lze zavolat pouze ve stavu
\textit{vypnuto}. Skončí-li bez výjimky, ovladač se nachází ve~stavu \textit{zapnuto}.
\item[void close()] Vypne server. Lze ji zavolat pouze ve stavu \textit{zapnuto}. Skončí-li bez výjimky, ovladač se
nachází ve stavu \textit{vypnuto}. Vypnutý ovladač lze znovu spus\-tit pomocí metody \lstinline!open!.
\end{sourcecodedesc}

Aplikace by měla před ukončením běhu vypnout všechny používané ovladače (pro každý zavolat metodu \lstinline!close()!).
Nebude-li tato podmínka splněna, může dojít k zablokování portů a ovladače nebude možné do restartu počítače znovu
spustit.

\subsection*{Ovládání robota}

Níže uvádíme metody třídy \lstinline!NabaztagProxy!, jejichž pomocí je možné ovlá\-dat robotické králíky \nab. Všechny
metody lze zavolat, pouze když je server ve stavu \textit{zapnuto}, jinak volání skončí výjimkou.

Všechny níže popsané metody jsou asynchronní -- úspěšné zavolání metody znamená, že konkrétní požadavek byl zařazen do
fronty a bude odeslán králíkovi v odpovědi na nejbližší \textit{ping} požadavek (viz popis komunikace mezi serverem
a~králíkem na stránce \pageref{sec:nab:protocol}). Níže uvedené metody odpovídají jednotlivým příkazům králíka:

\begin{sourcecodedesc}
\item[void reboot()] Restart králíka -- následuje vypnutí a zapnutí robota, který se znovu přihlásí k serveru a znovu
načte bootcode.
\item[void playSpeech(Speech s)] Požádá robota o přehrání záz\-namu zvuku \lstinline!s!. Podporované formáty jsou: WAV
(bez komprese nebo s kompresí ADPCM2) a MP3.
\item[void playUrl(String url)] Pošle požadavek na přehrávání streamova\-ného zvuku (typicky internetového rádia).
Podporovány jsou stejné formáty jako v~pří\-padě \lstinline!playSpeech!.
\item[void sendChoreography(String url)] Pošle požadavek na přehrání \textit{choreografie} (jedná~se o~posloupnost
příkazů, mezi kterými může být roz\-sví\-cení nebo vypnutí světla, změna pozic uší a pře\-hrá\-vání jednoduchých zvuků).
\item[void switchLedOn(Led led, Color c)] Pošle požadavek na rozsvěcení zvoleného světýlka na králíkovi.
\item[void switchLedOff(Led led)] Zařadí do fronty požadavek na vypnutí zvoleného světla na králíkovi.
\item[void moveEar(Ear e, int pos)] Požádá králíka o změnu pozice ucha. Parametr \lstinline!pos! určuje novou pozici
ucha (číslo v rozsahu $1$ -- $12$).
\item[void setPingFrequency(int newFrequency)] Změna časového intervalu, v ja\-kém králík kontroluje, zda na něj na
serveru čekají nějaké požadavky. Výchozí hodnota je $10$ vteřin. Čím menší je tato hodnota, tím rychleji bude králík
reagovat na uživatelské příkazy.
\end{sourcecodedesc}

\subsection*{Nastavení ovladače}

Níže popisujeme možnosti nastavení ovladače. Všechna jsou přístupná pomocí getter a setter metod v následujícím tvaru
(příklad pro \lstinline!listenerAddress! typu \lstinline!String!):
\begin{sourcecodedesc}
\item[String getListenerAddress()]Načte a vrátí hodnotu parametru.
\item[void setListenerAddress(String value)] Buď nastaví novou hodnotu parametru, nebo skončí výjimkou, je-li
hodnota
\lstinline!value! nekorektní nebo k~volání došlo ve špatném stavu.
\end{sourcecodedesc}

\noindent
Tento způsob přístupu ke konfiguraci umožňuje ovladač používat jako součást aplikace konfigurovanou prostřednictvím
Spring Frameworku, viz \ref{chap:spring}. Jedná se o způsob kompatibilní s IoC kontejnerem, který zpřístupňuje Spring
Framework a tím pádem je možné používat
ovladač jako součást aplikace konfigurované pomocí tohoto frameworku.

Všechny volby musí být určeny před spuštěním ovladače (tj. před zavoláním metody \lstinline!open()!), pozdější pokus
o~jejich změnu skončí výjimkou (server ale bude fungovat dál s původním nastavením). Nastavování parametrů serveru není
thread-safe, v případě přístupu z více vláken je nutná synchronizace. Gettery lze volat v libovolném stavu (jejich
volání by nikdy nemělo skončit výjimkou). Ovladač umožňuje nastavovat následující parametry:

\begin{sourcecodedesc}
\item[bootCodeLoader] Objekt, který umožňuje načtení bootcodu (operačního systému zařízení). Pro běžné použití by
mělo stačit výchozí nastavení (bootcode bude vždy načten z resourců -- \lstinline!/res/bootcode.bin!). Server nebude
fungovat s nejnovější verzí oficiálního bootcodu králíka \nab, která podporuje pouze protokol XMPP, nikoli HTTP
komunikaci).
\item[listenerAddress: String] Adresa a port (není-li uveden port, předpokládá se standardní HTTP port
$80$\footnote{Typicky pro spuštění ovladače na portu 80 uživatel musí mít administrátorská práva.}),
na kterou \nab{} posílá HTTP poža\-davky.
\item[maxQueueSize: int] Maximální velikost fronty požadavků ke zpracování. Je-li tato hodnota $\leq 0$, velikost fronty
není omezena.\footnote{Nicméně nedoporučujeme vypínat omezení velikosti fronty.} Výchozí hodnota je $10$.
\item[maxQueueSizeExceededBehavior: Enum] Určuje chování ovladače v případě
při\-jetí požadavku, jehož zařazení do
fronty by způsobilo překročení její maximální velikosti. Možné hodnoty:
\begin{description}[font=\ttfamily\small,leftmargin=0pt]
  \item[RemoveOldRequests] Nový požadavek je zařazen na konec fronty, ze které
je odstraněn
  nejstarší nezpracovaný požadavek (výchozí hodnota).
  \item[IgnoreNewRequests] Fronta se nemění, nový požadavek do ní není zařazen.
\end{description}
\item[suppressMultipleEvents: boolean] Tato volba určuje způsob, jakým ovladač
generuje udá\-losti
\lstinline!soundRecorded!. \nab{} posílá každý nahraný zvuk několikrát (dvakrát až čtyřikrát). Událost
\lstinline!soundRecorded! může nastat pokaždé, když králík pošle zá\-znam (nastavení \lstinline!false!, výchozí),
nebo pouze v případě, že daný záznam byl krá\-lí\-kem poslán poprvé (hodnota
\lstinline!true!).\footnote{Při tomto nastavení ovladač srovnává kontrolní součet nově přijatého zvuku s kontrolním
součtem předchozího zvuku. Jsou-li tyto hodnoty odlišné, dojde k vygenerování události.}
\item[threadPoolSize: int] Velikost fondu vláken (\textit{thread pool}), zpracovávajících HTTP poža\-davky králíka.
Tato hodnota musí být $\geq 1$. Výchozí nasta\-vení je $5$.\footnote{Nedoporučujeme používat příliš malou hodnotu
($1$~nebo $2$), může potom docházet ke zbytečně dlouhému čekání požadavků ve~frontě.}
\item[workingFolder: String] Cesta k adresáři, kde bude ovladač vytvářet do\-časné soubory (\textit{pracovní adresář}).
Je-li tento parametr \lstinline!null! (výchozí), vytvoří se podsložka ve standardním temp adresáři; ta bude automaticky
odstraněna při vypínání aplikace.\footnote{Pevné nastavení cesty pracovního adresáře je vhodné např. při debugování
ovladače nebo pluginů.}
\item[removeTempFiles: boolean] Určuje, zda dočasné soubory (např. vygenerované choreografie, výstup řečové syntézy)
mají být po odeslání robotovi odstraněny. Výchozí hodnota je \lstinline!true!.\footnote{Změna tohoto nastavení může být
užitečná při debugování.}
\end{sourcecodedesc}

\subsection*{Události}

Protože \java{}, na rozdíl od např. \csharp, neposkytuje přímou podporu
událostí, pro~rozesílání notifikací jiným
komponentám používáme návrhový vzor \textit{Pozorovatel} --
\textit{Observer} \cite{pecinovsky001}. Příjemci musí implementovat rozhraní
\lstinline!cz.cuni.mff.ufal.volk.NabaztagEventListener!.
Následující dvě metody umožňují změny seznamu notifikovaných komponent:
\begin{sourcecodedesc}
\item[void addListener(NabaztagEventListener o)] Pokud objekt \lstinline!o!
ještě nepatří do seznamu notifikovaných
objektů, bude do něj přidán.
\item[void removeListener(NabaztagEventListener o)] Pokud je objekt \lstinline!o!
součástí sez\-namu notifikovaných
objektů, bude z něj odebrán. 
\end{sourcecodedesc}
Obě výše zmíněné metody jsou synchronní (změny se projeví okamžitě po jejich zavolání) a můžou být volány v libovolném
stavu ovladače.

Existuje rovněž možnost přidat kolekci posluchačů jako parametr konstruktoru:\footnote{Tento konstruktor jsme zpřístupnili kvůli kompatibilitě s IoC kontejnerem Spring
Frameworku, díky tomu je možné určit
kolekci posluchačů přímo v konfiguračním souboru aplikace.}
\begin{sourcecodedesc}
\item[NabaztagControllerImpl(Collection<NabaztagEventListener> listeners)]
\end{sourcecodedesc}

Rozhraní \lstinline!cz.cuni.mff.ufal.volk.NabaztagEventListener! obsahuje
následu\-jící metody:

\begin{sourcecodedesc}
\item[void onStarted(NabaztagProxy sender)] K volání této metody dochází po
ús\-pěš\-ném odes\-lání bootcode (viz \ref{sec:nab:protocol}), možná i několi\-krát pro stejné zařízení (např. po restartu).

\item[void onClick(NabaztagProxy sender)] Metoda je volána po stisknutí tla\-čítka na hlavě krá\-líka (pouze
v případě, že se nejedná o nahrávání zvuku).
\item[void onDoubleClick(NabaztagProxy sender)] Metoda je volána poté, co
uživatel stiskne dvakrát tlačítko na hlavě
králíka.
\item[void onSoundRecorded(NabaztagProxy sender, Speech s)] Tato metoda je
vo\-lána poté, co~uživatel se
zmáčk\-nutým tlačítkem na hlavě králíka zaznamená zvuk. Nahraný zvuk je ve
formátu WAVE s kódováním ADPCM2.
K~vygenerování této události může dojít pro jeden záznam několikrát (\nab{}
posílá záznam tři- až čtyřikrát, důvod zatím
ne\-známe). Lze tomu zabránit nastavením volby
\lstinline!suppressMultipleEvents! na \lstinline!true!.
\item[void onCompleted(NabaztagProxy sender)] Tuto metodu server zavolá po úspěšném
provedení konkrétního pří\-kazu.
\item[void onTimeout(NabaztagProxy sender)] K volání této metody dojde poté, co
\nab{} obdrží odpověď \textit{timeout} ze
serveru.
\item[void onEarsMoved(NabaztagProxy sender, int left, int right)] K volání
metody dochází poté, co uži\-vatel ručně
změní pozici uší. Parametry \lstinline!left! a~\lstinline!right! určují novou
pozici levého, resp. pravého ucha (hodnota $1$ -- $12$, viz kapitola \ref{sec:nab:protocol}).
\item[void onVoiceInterrupted(NabaztagProxy sender)] Tato událost je generována poté,
co uživatel přerušil přehrávání zvuku stiskem tlačítka na hlavě králíka.
\end{sourcecodedesc}

Ovladač robota {\nab} je součástí knihovny \texttt{volk.jar}. Lze ho použít buď
jako nezávislou aplikaci nebo jako objekt z kódu jiného programu. V obou případech ovládač funguje jako HTTP server
postavený na \texttt{volkhs}. Je proto nezbytně nutné mít pro JVM povolena příchozí
připojení na daném portu, jinak se \nab{} nedokáže
připojit k serveru.

\subsection*{Použití ovladače}

Pro použití ovladače z kódu jiného programu je třeba vytvořit objekt typu
\lstinline!cz.cuni.mff.ufal.volk.NabaztagController!. Programátor má dvě základní možnosti:

\begin{enumerate}
  \item Samostatně naprogramovat vytváření objektu ovladače a předání všech
  potřebných závislostí. Tento postup je vhodný např. pro práci s konfigurací ve formátu nekompatibilním se Spring
  Frameworkem (viz příklad \ref{lib_ex_03}).
  \item Použít standardní konfigurační soubor Spring Framework, což je možné díky kompatibilitě s principem IoC (viz
příklad \ref{lib_ex_02}).
\end{enumerate}

\inclst{driver_manual_01}

\inclst{driver_manual_02}

\subsection{Generování sdělení na základě vzorců -- \lstinline!nlpat!}
\label{sec:nlpat}

Knihovna \lstinline!nlpat! umožňuje generovat zprávy na základě textových vzorců s použitím
formálního popisu jazyka a slovníku. Její součástí je jednoduchý popis českého
jazyka.

Vyhodnocování vzorců je implementováno v programovacím jazyce Prolog. Použili
jsme prostředí {\tuprolog} (viz \ref{chap:tools:prolog}).

Každý vzorec obsahuje \textit{formátovací řetězec} a \textit{podmínky}. K
oddělování těchto částí se používá speciální znak \texttt{\#}.

\subsubsection*{Formátovací řetězec}

\textit{Formátovací řetězec} je text s vnořenými parametry, které jsou po vyhodnocení nahrazovány konkrétními textovými
řetězci. Parametry jsou ve formátovacím řetězci uvedeny v následujícím tvaru:
\texttt{=název\_parametru=}. Název parametru musí začínat malým písmenem, potom
následuje posloupnost libovolně dlouhá posloupnost malých a velkých písmen anglické abecedy
(\azrange), číslic a podtržítek. Stejný parametr se může vyskytovat ve formátovacím
řetězci vícekrát; i v takovém případě budě pokaždé nahrazen stejným textem.

Formátovací řetězec může obsahovat speciální znaky \texttt{\#} a \texttt{=}.
Tyto znaky musí ale být escapovány pomocí zpětného lomítka --
\textbackslash (samotné zpětné lomítko je též třeba escapovat -- \textbackslash\textbackslash).

\subsubsection*{Podmínky}

Podmínky jsou ve své podstatě definicí procedury \texttt{cond/1}\footnote{Číslo za lomítkem označuje \textit{aritu}
(počet argumentů) objektu. V tomto konkrétním případě procedura \lstinline!cond! vyžaduje jeden parametr.} v jazyce
Prolog. Pro jejich základní použití není nutná pokročilá znalost Prologu, stačí následující zjednodušené
informace:\footnote{Stručný úvod do programování v Prologu v této kapitole je založen na \cite{kryl010}.}
\begin{description}
\item[Atomy (textové řetězce)] buď začínají malým písmenem a obsahují pouze malá
a velká písmena anglické abecedy, číslice a podtržítka, nebo jsou uzavřeny do
uvozovek. Např. \texttt{case}, \texttt{nom}, \texttt{gen}, \texttt{'krásná'},
\texttt{'Praha'}.
\item[Proměnné] vždy začínají velkým písmenem a skládají se z malých a velkých
písmen anglické abecedy, číslic a podtržítek. Např. \texttt{Name}, \texttt{Gen}.
\item[Seznam] je výčet prvků v hranatých závorkách. Jednotlivé prvky jsou
odděleny čárkou. Např. \lstinline![a, b, c]! (seznam, který  obsahuje tři atomy), \lstinline![X]! (libovolný
jednoprvkový seznam), \lstinline![]! (prázdný seznam).
\item[Klauzule] můžou určovat buď \textit{fakta} nebo \textit{pravidla}:


\begin{table}[ht!]
\begin{tabular}{|l|p{8cm}|}
\hline
Nápis & Význam \\ \hline
\texttt{s(a, b).} &  Vždy platí \lstinline!s(a, b).!\\ \hline
\texttt{s(A, B) :- c(A), d(A, B).} & Levá strana je pravdivá za předpokladu, že platí pravá strana.
\\
\hline
\end{tabular}
\end{table}
\item[Procedura] je posloupnost klauzulí (alternativ) se stejnou aritou.
\item[Řádkové komentáře] začínají znakem \lstinline!%!.
\end{description}

Jediný argument procedury \lstinline!cond/1! se unifikuje\footnote{\textit{Unifikace} je taková substituce proměnných
ve dvou (nebo více) prologovských termech, aby ve výsledky všechny termy byly stejné (až na názvy proměnných). Pro
podrobnější vysvětlení viz \cite{kryl010}.} se seznamem podmínek, které musí splňovat jednotlivé parametry ve
formátovacím řetězci. Existují dva typy podmínek:

\begin{description}
\item[\texttt{Param --> SeznamVlastnosti}] -- jedná se o určení vlastností, které
má splňovat parametr \textit{Param} načítaný ze slovníku.

Všechny vlastnosti jsou ve tvaru \texttt{NazevVlastnosti == Hodnota}. Název
vlastnosti musí být atom, hodnota může být buď atom nebo proměnná (hodí se
např. pro určování shody).
\item[\texttt{Param := Lit}] -- určení znakového řetězce, kterým má být nahrazen
parametr \textit{Param}. \textit{Param} musí být konkrétní název parametru,
nikoli proměnná.
\end{description}

Kvůli chybě parseru tuPrologu je třeba v podmínkách za tečku na konci klauzule vždy vkládat mezeru nebo znak nového
řádku. Tuto skutečnost je třeba si pamatovat
zejména při psaní víceřádkových vzorců přímo v kódu. Příklad \ref{patt_err_1}
obsahuje definici procedury \texttt{cond/1} pomocí dvou
klauzulí, které jsou odděleny pouze tečkou bez dodatečných bílých znaků.
Parsování neproběhne korektně. Za první tečku je proto nutné přidat mezeru
nebo znak nového řádku \texttt{\textbackslash n}.
\begin{lstlisting}[caption={Příklad chybného zadání vzorce.}, label=patt_err_1]
String pat = "=name= `ve svém příspěvku` =verb=, že...#" +
  "cond([verb := 'napsal', gen := 'm'])." +
  "cond([verb := 'napsala', gen := 'f']).";
\end{lstlisting}

\subsubsection*{Popis jazyka a slovník}

Slovník je definován prologovskou procedurou \lstinline!item(+Index, +Ort, +Features)!.\footnote{Znaky, které předchází
názvům parametrů v dokumentaci prologovských procedur, mají následující význam \cite{kryl010}:
\begin{sourcecodedesc}
\item[+] -- vstupní (již konkretizovaný parametr),
\item[-] -- výstupní parametr, na tomto místě může stát nekonkretizovaná proměnná,
\item[?] -- vstupní nebo výstupní parametr. \end{sourcecodedesc}} Výz\-nam jejích parametrů je popsán v
tabulce \ref{patt_item3_params}. Příklad \ref{patt_item3_example} obsahuje ukázkové slovníkové záznamy.

\begin{table}[ht!]
\begin{tabular}{|l|p{10cm}|}
\hline
Název parametru & Popis \\ \hline
\texttt{Index} & Index ve slovníku. \\ \hline
\texttt{Ort} & Pravopisný zápis konkrétní formy. Jelikož jde o již konkretizovaný parametr, musí se jednat o
atom. Zápis doporučujeme vždy uzavírat do uvozovek. \\ \hline
\texttt{Features} & Seznam \textit{rysů} ve tvaru \texttt{Nazev==Hodnota}.
\\ \hline
\end{tabular}
\caption{Popis argumentů procedury \texttt{item/3}.}
\label{patt_item3_params}
\end{table}

\begin{lstlisting}[caption={Ukázkové slovníkové záznamy.},
label=patt_item3_example]
item('go', 'jdu', [person==first, num==sg]).
item('go', 'jde', [person==third, num==sg]).
\end{lstlisting}

Při definování slovníku lze použít i pomocné predikáty. Součástí knihovny
\lstinline!nlpat! je jednoduchá morfologie českého jazyka. Přídavná jména (lze
přidat i~další slovní druhy) lze definovat pomocí predikátu
\lstinline!define_cz(+Index, +Root, +Type)!, není třeba vyjmenovávat všechny možné
tvary. Popis parametrů je uveden v tabulce \ref{patt_definecz3_params}. Např.
přídavné jméno \textit{krásný} lze do slovníku přidat následujícím způsobem:
\lstinline!`define_cz(beautiful, 'krásn', adjh)`!.

\begin{table}
\begin{tabular}{|l|p{10cm}|} \hline
Název parametru & Popis \\ \hline
\texttt{Index} & Index ve slovníku. \\ \hline
\texttt{Root} & Kmen slova (včetně morfologického vzoru). \\ \hline
\texttt{Type} & Slovní druh. Podporovány jsou dva typy:
\begin{description}
\item[adjh] tvrdé přídavné jméno (např. \textit{krásný})
\item[adjw] měkké přídavné jméno (např. \textit{jarní})
\end{description} \\ \hline
\end{tabular}
\caption{Popis argumentů procedury \lstinline!define\_cz/3!.}
\label{patt_definecz3_params}
\end{table}

\subsubsection*{Vyhodnocování}

Vyhodnocování vzorců zajišťuje javovská metoda \lstinline!String evaluate(String... params)! třídy
\lstinline!cz.cuni.mff.ufal.volk.patterns.Pattern!. Přijímá sudý počet argumentů -- střídavě názvy parametrů ze
vzorce a literály nebo slovníkové indexy se znakem \lstinline!@! na začátku. Pokud literál začíná znakem \lstinline!@!,
je třeba ho zdvojit. Příklad \ref{patt_example_0} ukazuje kompletní kód v Javě pro vytvoření textové zprávy.

\begin{lstlisting}[label=patt_example_0, caption={Příklad použití modulu
\texttt{nlpat}. Předpokládá se, že program má přístup k souboru
\texttt{pl/cz\_lang.pl} a že tento soubor obsahuje správnou definici jazyka.}]
// `povinné importy, dál se používají pouze názvy tříd`
import alice.tuprolog.InvalidTheoryException;
import cz.cuni.mff.ufal.volk.patterns.LanguageDescription;
import cz.cuni.mff.ufal.volk.patterns.Pattern;

LanguageDescription czechDesc;
FileInputStream in = new FileInputStream("pl/cz_lang.pl");
try {
  czechDesc = new LanguageDescription(in);
} finally {
  in.close();
}
Pattern pat = new Pattern(desc, "Ty jsi =b= holka.#" +
  "cond([b-->[case == nom, num == sg, gen == fem]]).");
String out = pat.evaluate("b", "@beautiful");
\end{lstlisting}

\subsubsection*{Příklady použití}

Příklady použití (všechny níže uvedené příklady jsou součástí testovacího balíku \texttt{cz.cuni.mff.ufal.volk.patterns.test}):

\begin{itemize}
  \item Výběr koncovky přídavného jména podle rodu. Koncovka je pevně zadaná v kódu, slovo pochází ze slovníku.
    \begin{lstlisting}
Toto je `krásn`=ending= =noun=.#
  cond([ending:='`á`',
    noun-->[case==nom, num==sg, gen==fem]]).
  cond([ending:='`ý`',
    noun-->[case==nom, num==sg, gen==masc]]).
\end{lstlisting}
Kód: \lstinline!pat.evaluate("noun", "@hedgehog");!\\
Výsledek: \textit{Toto je krásný ježek.}
  \item Shoda podstatného a přídavného jména v rodě:
  \begin{lstlisting}
  =a= =n= =v=#
  cond([
    a --> [case==nom, num==sg, gen == G],
    n --> [case==nom, num==sg, gen==G],
    v --> [person==third, num==sg]
  ]).");
  \end{lstlisting}
Kód: \lstinline!pat.evaluate("a", "@beautiful", "n", "@girl", "v", "@eat");!\\
Výsledek: \textit{krásná holka jí}
\item Shoda podstatného jména a slovesa v rodě. V tomto příkladu se ne\-po\-u\-žívá slovník; slova, kterými mají být
nahrazeny proměnné, jsou zakódovánas ve vzorci.
\begin{lstlisting}
=name= =verb=, `že`...#
  cond([verb := 'napsal', gen := 'm']).
  cond([verb := 'napsala', gen := 'f']).
\end{lstlisting}
Kód: \lstinline!pat.evaluate("name", "Magda", "gen", "f");!\\
Výsledek: \textit{Magda napsala, že...}
\end{itemize}

\subsection{Rozpoznání jazyka -- \lstinline!tool_langr!}

Knihovna \lstinline!tool_langr! slouží jako implementace rozpoznávání jazyka psaného textu. Zakládá se na n-gramovém
(viz \cite{manning010}) jazykovém modelu (číslo $n$ je parametrizovatelné) nad znaky. Trénovací data pro každý jazyk by měla
být rozdělena na část pro samotné trénování a část, která bude použita pro vyhlazování jednotlivých jazykových modelů.

Hlavní třídou této komponenty je \lstinline!NgramLanguageRecognizer! (jakožto implementace rozhraní
\lstinline!LanguageRecognizer!). Příprava její instance, která umožňuje rozpoznat jazyk textu, probíhá ve dvou fázích:
\begin{enumerate}
  \item Volání konstruktoru \lstinline!NgramLanguageRecognizer(Mode mode)!. Parametr je nepovinný, rozpoznávání jazyka
  funguje s výchozí hodnotou \lstinline!Mode.Normal!.
  \item Volání metody \lstinline!void train(File source, int n)!, která slouží trénování jazykových modelů; popis
  para\-met\-rů se nachází v tabulce \ref{tab:040:params:train}. Při testování (polština,
čeština, slovenština, maďarština a kašubština) jsme zjistili, že kvalita rozpoznávání je vyhovující již pro $n=5$
(úspěšnost $93,37\%$ pro použitá testovací data). Zvětšování čísla $n$ způsobuje významné zpomalení procesu trénování a
zvětšení modelu ($11$MB pro $n=6$ oproti $6$MB pro $n=5$) a nemá skoro žádný vliv na kvalitu rozpoznávání. Po
nastavení $n=6$ jsme dokonce zaznamenali mírný pokles úspěšnosti na $93,20\%$.
\end{enumerate}

\begin{table}[ht!]
\centering
\begin{tabular}{|m{3cm}|m{10.0cm}|}
\hline
Parametr & Popis \\ \hline
\lstinline!source! & Adresář, kde se nachází trénovací data. Jeho struktura musí vypadat takto:
\dirtree{%
.1 ./.
.2 train/.
.3 \normalfont{soubory s trénovacími daty}.
.2 smooth/.
.3 \normalfont{soubory s daty používanými pro vyhlazování modelů}.
}
Každý podporovaný jazyk musí být zastoupen jedním souborem v každém z podadresářů; jeho názvem je ISO-639 kód
jazyka bez přípony, např. \lstinline!cs!, \lstinline!sk!, \lstinline!pl!.
\\ \hline
\lstinline!n! & Úroveň (maximální délka n-gramů, pro které se počítá pravděpodobnost) modelů. 
\\
\hline
\end{tabular}
\caption{Popis parametrů metody \lstinline!NgramLanguageRecognizer.train!.}
\label{tab:040:params:train}
\end{table}

Hotový model lze serializovat do souboru a takto distribuovat, aniž by bylo nutné poskytovat trénovací data -- to má dvě
hlavní výhody:
\begin{enumerate}
  \item Trénování může trvat delší dobu (řadově až desítky minut), takže serializace vede k výrazné časové úspoře.
  \item Mají-li být trénovací data veřejně přístupná, poskytovatel musí použít pouze texty, které má právo veřejně
  distribuovat. Tento problém odpadá, je-li možné uživatelům dodat pouze jazykový model.
\end{enumerate}

V resources balíčku \lstinline!tool_langr.jar! je jako \lstinline!model/slav1.nmodel! zpřístupněn serializovaný objekt,
který umožňuje rozpoznávání češtiny (\lstinline!cs!), slovenštiny (\lstinline!sk!), polštiny (\lstinline!pl!), maďarštiny (\lstinline!hu!) a kašubštiny
(\lstinline!csb!). Podporuje rozpoznávání jazyků pro texty s diakritikou i bez ní.\footnote{Jako trénovací data byly
použity texty z Wikipedie v příslušných jazycích. Jazykové modely jsou pětigramové.}

Zatím je v resources jenom jeden model, lze nicméně serializovat a přidat další modely. Jednoduchý přístup k
serializovaným modelům zajišťuje třída \lstinline!ResourceLanguageRecognizer!. Způsob načítání modelů pro rozpoznávání
jazyka je znázorněn v příkladech \ref{listing:040:rlr:java} a \ref{listing:040:rlr:spring}. 
\begin{lstlisting}[breaklines=true, breakatwhitespace=true,
caption={Příklad kódu pro načtení serializovaného modelu z resources balíčku \lstinline!tool_langr.jar!.},
label=listing:040:rlr:java] 
LanguageRecognizer<Text> rec =
  new ResourceLanguageRecognizer("slav1.nmodel");
\end{lstlisting}

\begin{lstlisting}[breaklines=true, breakatwhitespace=true, caption={Příklad načtení serializovaného
modelu z balíčku \lstinline!tool_langr.jar! s použitím Spring Frameworku. Nejedná se o kompletní konfiguraci,
pouze o část, která zodpovídá za načtení objektu.}, label=listing:040:rlr:spring]
<bean id="volk.langrec" class="cz.cuni.mff.ufal.volk.langr.
    ResourceLanguageRecognizer">
  <constructor-arg value="slav1.nmodel" />
</bean>
\end{lstlisting}
